#!/usr/bin/env sh

#  helper script: download coreboot
#
#	Copyright (C) 2014-2016,2020,2021,2023 Leah Rowe <info@minifree.org>
#	Copyright (C) 2022 Alper Nebi Yasak <alpernebiyasak@gmail.com>
#	Copyright (C) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

[ "x${DEBUG+set}" = 'xset' ] && set -v
set -u -e

_board=""
cbtree=""
cbrevision=""

# NODELETE= ./download coreboot
# usage: NODELETE= ./download coreboot
# if you do this, .git* won't be removed, nor will blobs
# this is useful for working on patches to a coreboot tree,
# in git, then then add in the build system
nodelete="false"
if [ "x${NODELETE+set}" = 'xset' ]; then
	nodelete="true"
fi

cbcfgsdir="resources/coreboot"

main()
{
	rm -f ${cbcfgsdir}/*/seen

	printf "Downloading coreboot and (if available) applying patches\n"

	boards=""
	if [ $# -gt 0 ]; then
		boards=$@
	else
		for board in "${cbcfgsdir}/"*; do
			[ ! -d "${board}" ] && continue
			boards="${boards} ${board##*/}"
		done
	fi
	for board in ${boards}; do
		rm -f "${cbcfgsdir}"/*/seen
		download_coreboot_for_board "${board}"
	done

	censor_blobs
	rm -f ${cbcfgsdir}/*/seen
}

download_coreboot_for_board()
{
	_board="${1}"
	cbtree="undefined"
	cbrevision="undefined"

	fetch_coreboot_config "${_board}" || exit 1

	rm -f "${cbcfgsdir}"/*/seen

	if [ -d "coreboot/${cbtree}" ]; then
		printf "REMARK: download/coreboot %s: exists. Skipping.\n" \
				${cbtree}
		[ "${cbtree}" != "${1}" ] && \
			printf "(for board: '%s}')\n" ${1}
		return 0
	fi

	gitclone_coreboot_from_upstream || exit 1

	prepare_new_coreboot_tree "${1}" "${cbtree}" "${cbrevision}" \
			|| exit 1
}

fetch_coreboot_config()
{
	_board=${1}

	while true; do
		cbrevision="undefined"
		cbtree="undefined"

		check_config_for_board "${_board}" || return 1

		# This is to override $cbrevision and $cbtree
		. "${cbcfgsdir}/${_board}/board.cfg" || exit 1

		if [ "${_board}" != "${cbtree}" ]; then
			_board="${cbtree}"
			continue
		elif [ "${cbtree}" = "undefined" ]; then
			printf "ERROR: download/coreboot:"
			printf " tree name undefined for '%s\n'" \
					${_board}
			return 1
		elif [ "${cbrevision}" = "undefined" ]; then
			printf "ERROR: download/coreboot:"
			printf " commit ID undefined for '%s'\n" \
					${_board}
			return 1
		else
			break
		fi
	done
}

check_config_for_board()
{
	_board=${1}

	if [ ! -f "${cbcfgsdir}/${_board}/board.cfg" ]; then
		printf "ERROR: download/coreboot: board.cfg does not"
		printf " exist for '%s'\n" ${_board}
		return 1
	elif [ -f "${cbcfgsdir}/${_board}/seen" ]; then
		printf "ERROR: download/coreboot: logical loop:"
		printf " '%s' board.cfg refers to another tree," ${_board}
		printf " which ultimately refers back to '%s'." ${_board}
		return 1
	fi
	touch "${cbcfgsdir}/${_board}/seen"
}

gitclone_coreboot_from_upstream()
{
	[ ! -d coreboot ] && \
		mkdir -p coreboot
	[ ! -d coreboot ] && \
		return 1
	[ -d coreboot/coreboot ] && \
		return 0
	./gitclone coreboot || \
		return 1
}

prepare_new_coreboot_tree()
{
	target=${1}
	cbtree=${2}
	cbrevision=${3}

	printf "Preparing coreboot tree: %s\n" ${cbtree}
	[ "${cbtree}" != "${target}" ] && \
		printf "(for board: %s)\n" "${target}"

	cp -R coreboot/coreboot "coreboot/${cbtree}" || exit 1
	(
	cd "coreboot/${cbtree}" \
		|| err "cannot cd to coreboot/${cbtree}"
	git reset --hard ${cbrevision} \
		|| err "cannot reset coreboot revision for tree, ${cbtree}"
	git submodule update --init \
		|| err "cannot update coreboot submodules for tree, ${cbtree}"

	for patch in ../../"${cbcfgsdir}"/"${cbtree}"/patches/*.patch; do
		[ ! -f "${patch}" ] && \
			continue
		if ! git am "${patch}"; then
			git am --abort
			err "cannot patch ${cbtree}"
		fi
	done

	# extra.sh can be used for anything
	# but should *only* be a last resort
	if [ -f "../../${cbcfgsdir}/${cbtree}/extra.sh" ]; then
		"../../${cbcfgsdir}/${cbtree}/extra.sh" || \
			err "${cbtree} extra.sh"
	fi
	)
}

censor_blobs()
{
	if [ "${nodelete}" = "true" ]; then
		return
	fi

	printf "Doing this to coreboot: https://en.wikipedia.org/wiki/Book_burning\n"
	printf "Whatever you do, don't read: https://libreboot.org/news/policy.html\n"

	rm -Rf coreboot/coreboot/
	rm -Rf coreboot/.git* coreboot/*/.git* \
			coreboot/*/3rdparty/*/.git*
	rm -Rf coreboot/*/util/nvidia/cbootimage/.git*

	# Also delete that nasty evil documentation that
	# tells users how to install coreboot, because those
	# evil coreboot people recommend blobs sometimes. /s
	rm -Rf coreboot/*/Documentation

	# it's basically book-burning. GNU FSDG policy == censorship.
	# https://en.wikipedia.org/wiki/Book_burning

	# there is a much better way:
	# https://libreboot.org/news/policy.html

	# but this version of libreboot is designed for the FSF
	# to use in their GNU Boot project.

	# and i guarantee you, they will remove the above comments
	# if they fork this code.

	# *they* will call it FREEDOM.

	# but it's not. they're removing your freedom to choose.
	# and censoring everything they don't like.

	# they will decide what is good for you.
	# they will decide against you.
	# and if you fell for their propaganda, you'll feel
	# pure. despite the fact that your machine is still
	# full of blobs, even if the boot flash is blob-free.
	# see:
	# https://libreboot.org/faq.html#what-other-firmware-exists-outside-of-libreboot

	# this, despite the fact that libreboot is a free software
	# project. they call it non-free. the truth is written here:

	# https://libreboot.org/freedom-status.html

	for cbdir in coreboot/*; do
		if [ ! -d "${cbdir}" ]; then continue; fi
		cbtree="${cbdir##coreboot/}"
		cbtree="${cbtree%/}"
		if [ ! -d "coreboot/${cbtree}" ]; then continue; fi
		bloblist="resources/coreboot/${cbtree}/blobs.list"
		if [ -f "${bloblist}" ]; then
			for blobfile in $(cat "${bloblist}"); do
				printf "Deleting blob: 'coreboot/%s/%s'\n" \
						"${cbtree}" "${blobfile}"
				rm -f "coreboot/${cbtree}/${blobfile}"
			done
		else
			printf "WARNING blobs.list unavailable for %s" \
				${cbtree} 1>&2
		fi
		rmlist="resources/coreboot/${cbtree}/rm.list"
		if [ -f "${rmlist}" ]; then
			for rmentry in $(cat "${rmlist}"); do
				printf "Deleting directory to save space: "
				printf "'coreboot/%s/%s'\n" \
						"${cbtree}" "${rmentry}"
				rm -Rf "coreboot/${cbtree}/${rmentry}"
			done
		fi
	done

}

err()
{
	printf "ERROR: %s: %s\n" $0 $1 1>&2
	exit 1
}

main $@
